/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "dns_option_internal.h"
#include "securec.h"
#include "log.h"

namespace ImageKnifePro {

// static
std::shared_ptr<DnsOption> DnsOption::CreateDnsOption(std::vector<StaticDnsRuleItem> &&staticDnsRule)
{
    return std::make_shared<DnsOptionInternal>(std::move(staticDnsRule));
}

// static
std::shared_ptr<DnsOption> DnsOption::CreateDnsOption(const std::vector<StaticDnsRuleItem> &staticDnsRule)
{
    return std::make_shared<DnsOptionInternal>(staticDnsRule);
}

DnsOptionInternal::DnsOptionInternal(std::vector<StaticDnsRuleItem> &&staticDnsRule)
    : staticDnsRule_(std::move(staticDnsRule))
{
    CovertRcpStaticDnsRule();
}

DnsOptionInternal::DnsOptionInternal(const std::vector<StaticDnsRuleItem> &staticDnsRule)
    : staticDnsRule_(staticDnsRule)
{
    CovertRcpStaticDnsRule();
}

const std::vector<StaticDnsRuleItem> &DnsOptionInternal::GetStaticDnsRule()
{
    return staticDnsRule_;
}

Rcp_DnsRule *DnsOptionInternal::GetRcpDnsRule()
{
    if (rcpStaticDnsRule_ == nullptr) {
        return nullptr;
    }
    return &rcpDnsRules_;
}

bool CreateRcpDnsRuleItem(Rcp_StaticDnsRuleItem &rcpRuleItem, const StaticDnsRuleItem &item)
{
    if (item.ipAddresses.empty()) {
        IMAGE_KNIFE_LOG(LOG_WARN, "StaticDnsRuleItem ipAddresses is empty");
        return false;
    }

    rcpRuleItem.port = item.port;
    (void)memcpy_s(rcpRuleItem.host, RCP_HOST_MAX_LEN, item.host.c_str(), item.host.size() + 1);

    rcpRuleItem.ipAddresses = nullptr;
    Rcp_IpAddress *point = nullptr;
    for (auto &ipAddress : item.ipAddresses) {
        Rcp_IpAddress *address = new Rcp_IpAddress;
        (void)memcpy_s(address->ipAddress, RCP_IP_MAX_LEN, ipAddress.c_str(), ipAddress.size() + 1);
        if (rcpRuleItem.ipAddresses == nullptr) {
            rcpRuleItem.ipAddresses = address;
            point = address;
        } else {
            point->next = address;
            point = address;
        }
    }
    point->next = nullptr;

    return true;
}

void DnsOptionInternal::CovertRcpStaticDnsRule()
{
    if (staticDnsRule_.empty()) {
        return;
    }

    // 避免重复解析
    if (rcpStaticDnsRule_ != nullptr) {
        return;
    }

    Rcp_StaticDnsRule *point = nullptr;
    Rcp_StaticDnsRule *temp = nullptr;
    for (auto &item : staticDnsRule_) {
        if (temp == nullptr) {
            temp = new Rcp_StaticDnsRule;
        }
        if (!CreateRcpDnsRuleItem(temp->staticDnsRule, item)) {
            continue;
        }

        if (rcpStaticDnsRule_ == nullptr) {
            rcpStaticDnsRule_ = temp;
            point = temp;
        } else {
            point->next = temp;
            point = temp;
        }
        temp = nullptr;
    }

    // 删除未使用的创建失败的item节点
    if (temp != nullptr) {
        delete temp;
    }

    point->next = nullptr;
    rcpDnsRules_.type = RCP_DNS_RULE_STATIC;
    rcpDnsRules_.data.staticDnsRule = rcpStaticDnsRule_;
}

void DnsOptionInternal::TraversingRcpDnsRule()
{
    int index = 0;
    Rcp_StaticDnsRule *rulePoint = rcpStaticDnsRule_;
    while (rulePoint != nullptr) {
        Rcp_IpAddress *point = rulePoint->staticDnsRule.ipAddresses;
        IMAGE_KNIFE_LOG(LOG_INFO, "RcpDnsRule[%{public}d], host:%{public}s, port:%{public}d, IpAddresses:", index,
                        rulePoint->staticDnsRule.host, rulePoint->staticDnsRule.port);
        int i = 0;
        while (point != nullptr) {
            IMAGE_KNIFE_LOG(LOG_INFO, "---> RcpDnsRule[%{public}d], IpAddress[%{public}d]: %{public}s",
                            index, i, point->ipAddress);
            Rcp_IpAddress *next = point->next;
            point = next;
            i++;
        }

        rulePoint = rulePoint->next;
        index++;
    }
}

DnsOptionInternal::~DnsOptionInternal()
{
    // 释放rcp dns rule链表
    while (rcpStaticDnsRule_ != nullptr) {
        // 释放每个rule item中的ipAddresses链表
        Rcp_IpAddress *point = rcpStaticDnsRule_->staticDnsRule.ipAddresses;
        while (point != nullptr) {
            Rcp_IpAddress *next = point->next;
            delete point;
            point = next;
        }

        Rcp_StaticDnsRule *nextRule = rcpStaticDnsRule_->next;
        delete rcpStaticDnsRule_;
        rcpStaticDnsRule_ = nextRule;
    }
}

}

